#include "monitor.h"
#include "expr.h"
#include "watchpoint.h"
#include "temu.h"

#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <OS_gui.h>

void cpu_exec(uint32_t);
void display_reg();

/* We use the `readline' library to provide more flexibility to read from stdin. */
char* rl_gets() {
	static char *line_read = NULL;

	if (line_read) {
		free(line_read);
		line_read = NULL;
	}

	// line_read = readline("(temu) ");
	
	if (line_read && *line_read) {
		add_history(line_read);
	}

	return line_read;
}

static int cmd_c(char *args) {
	cpu_exec(-1);
	return 0;
}

static int cmd_q(char *args) {
	return -1;
}

static int cmd_si(char *args){
	if(args==NULL)cpu_exec(1);
	else{
		int i = 0;
		int n = 0;
		while(args[i]!='\0')
		{
			n = 10*n + (int)(args[i] - '0');
			i++;
		}
		cpu_exec(n);
	}
	return 0;
}

static int cmd_info(char *args){
	if(args[0]=='r'){
		display_reg();
	else if(args[0]=='w'){
		wpCheck();
	}
	else assert(0);	
	return 0;
}

static int cmd_help(char *args);
static int cmd_p(char *args);
static int cmd_w(char* args);
static int cmd_d(char* args);

static struct {
	char *name;
	char *description;
	int (*handler) (char *);
} cmd_table [] = {
	{ "help", "Display informations about all supported commands", cmd_help },
	{ "c", "Continue the execution of the program", cmd_c },
	{ "q", "Exit TEMU", cmd_q },
	{ "si","single steps",cmd_si},
	{ "info","print registers",cmd_info},
	{ "p", "Calculate the value of an expression", cmd_p},
	{ "w", "Add a watch point", cmd_w},
	{ "d", "Delete a watch point", cmd_d}

	/* TODO: Add more commands */

};

#define NR_CMD (sizeof(cmd_table) / sizeof(cmd_table[0]))

static int cmd_help(char *args) {
	/* extract the first argument */
	char *arg = strtok(NULL, " ");
	int i;

	if(arg == NULL) {
		/* no argument given */
		for(i = 0; i < NR_CMD; i ++) {
			GUI_printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description);
		}
	}
	else {
		for(i = 0; i < NR_CMD; i ++) {
			if(strcmp(arg, cmd_table[i].name) == 0) {
				GUI_printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description);
				return 0;
			}
		}
		GUI_printf("Unknown command '%s'\n", arg);
	}
	return 0;
}

static int cmd_p(char* args){
	bool success = false;
	int res = expr(args, &success);
	if(success == 1) GUI_printf("%d (0x%x)\n", res, res);
	else GUI_printf("\33[1;31mExpression calculate failed.\33[0m\n");
	return 0;
}

static int cmd_w(char* args){
	wpAdd(args);
	return 0;
}

static int cmd_d(char* args){
	wpDel(args);
	return 0;
}

void ui_mainloop() {
	while(1) {
		
		draw_All();
		if(GUI_helper() < 0) return;
		// switch_Mode();

		// char *str = rl_gets();
		// char *str_end = str + strlen(str);

		/* extract the first token as the command */
		// char *cmd = strtok(str, " ");
		// if(cmd == NULL) { continue; }

		/* treat the remaining string as the arguments,
		 * which may need further parsing
		 */
		// char *args = cmd + strlen(cmd) + 1;
		// if(args >= str_end) {
		// 	args = NULL;
		// }

		// int i;
		// for(i = 0; i < NR_CMD; i ++) {
		// 	if(strcmp(cmd, cmd_table[i].name) == 0) {
		// 		if(cmd_table[i].handler(args) < 0) { return; }
		// 		break;
		// 	}
		// }

		// if(i == NR_CMD) { GUI_printf("Unknown command '%s'\n", cmd); }
		// if(i == NR_CMD) { 
		// 	GUI_printf("Unknown command '%s'\n", cmd);
		// }
	}
	
}
